#!/bin/sh /usr/pkg/bin/bash /usr/local/bin/bash

# CF Final SVN Tag Id: cf_image.sh 172 2007-02-20 20:42:24Z seklecki
# Google SVN $Id$
# ====

#/*
# * Copyright (c) 2006-2007 Collaborative Fusion, Inc.  All rights reserved.
# * 
# * Developed by: Collaborative Fusion, Inc.
# *                                                     http://www.collaborativefusion.com
# * 
# * Permission is hereby granted, free of charge, to any person obtaining a copy
# * of this software and associated documentation files (the "Software"), to
# * deal with the Software without restriction, including without limitation the
# * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# * sell copies of the Software, and to permit persons to whom the Software is
# * furnished to do so, subject to the following conditions:
# *   1. Redistributions of source code must retain the above copyright notice,
# *      this list of conditions and the following disclaimers.
# *   2. Redistributions in binary form must reproduce the above copyright
# *      notice, this list of conditions and the following disclaimers in the
# *      documentation and/or other materials provided with the distribution.
# *   3. All advertising materials mentioning features or use of this software
# *      must display the following acknowledgement: This product includes 
# *      software developed by Collaborative Fusion, Inc.
# *   4. Neither the name of Collaborative Fusion, Inc. or any of its employees
# *      may be used to endorse or promote products derived from this Software
# *      without specific prior written permission.
#
# * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
# * COLLABORATIVE FUSION, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
# * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# */
#
#/*
# * This code was written under funding by Collaborative Fusion, Inc..
# */


# Copyright 2003 Gray Watson
#
# Permission to use, copy, modify, and distribute this software for
# any purpose and without fee is hereby granted, provided that the
# above copyright notice and this permission notice appear in all
# copies, and that the name of Gray Watson not be used in advertising
# or publicity pertaining to distribution of the document or software
# without specific, written prior permission.
#
# Gray Watson makes no representations about the suitability of the
# software described herein for any purpose.  It is provided "as is"
# without express or implied warranty.
#
# The author may be contacted via http://256.com/gray/
#
# This script builds a boot image to be written to a compact flash
# device and booted in a Soekris system.  More information online:
#
# http://256.com/gray/docs/soekris_openbsd_diskless/


if [ ! -f "./cf.conf" ]; then
        echo "Cannot find cf.conf in ./ ...bailing out!";
        exit 1;
else
        source ./cf.conf
fi

trap cleanup 1 2 3 14 15

# override until we can sanitize variable names:
IMAGE_FILE=./cfimages/image_cf.$(date "+%Y%m%d%H%M").${UFQDN}.$(uname -mrs | sed s/\ /\_/g)
# NetBSD-specific to vnd(4)
VNODE_MOUNT=./__mount_cf__
DEFAULT_ROOT=./cf_root
DISKLABEL_TMP=cf.$$.t
DISKLABEL_TMP="$(${DISKLABEL_TMP_COMMAND})"

A_SLICE_MB_DEFAULT=96

_intStepCount=0;

cat << __EOF
Building CF media image for $PLATFORM
Copyright 2003 Gray Watson
-------------------------------------
NetBSD adjustments 04/06 by Brian A. Seklecki <lavalamp@spiritual-machines.org>
				 by Brian A. Seklecki <bseklecki@collaborativefusion.com>

__EOF

#################################################

echo -n "Enter the filename to write the image into: [$IMAGE_FILE] "
read image_file
if [ "$image_file" = "" ]; then
    image_file=$IMAGE_FILE
fi

#################################################

cat << __EOF
----------
Type in size of CF card in MB.  Either: 32, 64, 128, 256.

If your size isn't in the above list then insert the CF card into your
Soekris box and boot it and write down what it says.  When it boots it
should say:

    Pri Mas [ Name of CF Card ]   LBA: CCC-TT-SS  MMM MByte.

The CCC is the number of cylinders, TT is the tracks per cylinder, and SS
is the sectors per track.  The MMM is the number of megabytes on the card
with some space removed for rounding.

__EOF
echo -n "Enter size in MB or just press enter to type in drive specs "
echo -n "(32, 64, 128, 256, 1g, 1gVmWare, 1gbSanDiskUltraII, 2gbSanDiskUltraII, 2gbKingstonElitePro50x, 1gbApacer88x): "
read cf_size

case $cf_size in 
    32)
	# 32mb CF
	sectors_track=32	# "sectors/track:"
	tracks_cylinder=8	# "tracks/cylinder:"
	cylinders=245		# "cylinders:"
	;;
    64)
	# 64mb CF
	sectors_track=32	# "sectors/track:"
	tracks_cylinder=8	# "tracks/cylinder:"
	cylinders=490		# "cylinders:"
	;;
    128)
	# 128Meg CF
	sectors_track=32	# "sectors/track:"
	tracks_cylinder=64      # "tracks/cylinder:"
	cylinders=122		# "cylinders:"
	;;
    256soeksnapshot)
	# Unknown manufac 256mb CF from Gonzalo Urioste @ Soekris list (256376832 bytes)
	sectors_track=32	# "sectors/track:"
	tracks_cylinder=8	# "tracks/cylinder:"
	cylinders=1956		# "cylinders:"
	;;
    256)
	# 256Meg CF
	sectors_track=32	# "sectors/track:"
	tracks_cylinder=16      # "tracks/cylinder:"
	cylinders=980		# "cylinders:"
	;;
    1g)
	# 1g CF
	sectors_track=63	# "sectors/track:"
	tracks_cylinder=512      # "tracks/cylinder:"
	cylinders=78		# "cylinders:"
	;;
    1gVmWare)
	# 1g Virtual VMWARE (1024mb)
	sectors_track=63	# "sectors/track:"
	tracks_cylinder=16      # "tracks/cylinder:"
	cylinders=2080		# "cylinders:"
	;;
    1gbSanDiskUltraII)
	# 1GB SanDisk Ultra II
	sectors_track=63	# "sectors/track:"
	tracks_cylinder=16      # "tracks/cylinder:"
	cylinders=1986		# "cylinders:"
	;;
    2gbSanDiskUltraII)
	# 2GB SanDisk Ultra II
	sectors_track=63	# "sectors/track:"
	tracks_cylinder=16      # "tracks/cylinder:"
	cylinders=3970		# "cylinders:"
	;;
    2gbKingstonElitePro50x)
	# 2GB Kingston Elite Pro 50x
	sectors_track=32	# "sectors/track:"
	tracks_cylinder=16      # "tracks/cylinder:"
	cylinders=7872		# "cylinders:"
	;;
    1gbApacer88x)
	# 1 Gig Apacher Photo 88X via Nexcom
	sectors_track=63	# "sectors/track:"
	tracks_cylinder=16      # "tracks/cylinder:"
	cylinders=2014		# "cylinders:"
	;;
    *)
	echo -n "Enter cylinders: "
	read cylinders
	echo -n "Tracks per cylinder: "
	read tracks_cylinder
	echo -n "Sectors per track: "
	read sectors_track
	;;
esac

#################################################
# almost always a universal constant?
bytes=512

# Calculate our total size of the image in 512b blocks

# For use by NetBSD-only
# NetBSD defines "c:" as $total_blocks - ( 1 x $sector_track)
# Presumably to leave sufficient space of MBR/Boot/Etc.
# But a "d:" slice is a legacy thing that represents the entire drive
total_blocks=`expr $cylinders \* $tracks_cylinder \* $sectors_track`
total_bytes=`expr $total_blocks \* $bytes`

# for "c:"
total_blocks_usable=`expr $total_blocks \- $sectors_track`
total_bytes_usable=`expr $total_blocks_usable \* $bytes`

# calculate sectors per cylinder
sectors_cylinder=`expr $tracks_cylinder \* $sectors_track`

#### STRATEGY CHANGE ####
#### Brian Seklecki
# I'm working with 1gb/2gb flash cards instead of 256mb So my strategy is
# different: I want to break the CF card into two partitions: 
# -- 512mb a: slice and the remainer in b: for the following purposes:
# a: boostrap slice where usr.tgz, /netbsd, /boot reside
# b: system-specific read-write shadow file system

# this is to calculate an "A" size 1 cylinder less than
# total for "B", but we're not using that method
## #
## # From flashdist.sh by Chris Cappuccio and modified by Ron Rosson.
## # Here we remove additional cylinders while
## # (totalsize <= (cylinders*(sectors/cylinder))) so that
## # we have room for the b partition and still lie on a cylinder boundary:
## #
## while [ "$total_blocks" -le "$a_blocks" ]; do
##     a_blocks=`expr $a_blocks - $sectors_cylinder`
## done

# We don't need this either since we're building
# the label with an offset of 1 * $sectors_track
## remove the first track where the disklabel goes
##a_blocks=`expr $a_blocks - $sectors_track`

# Remember: "blocks" quantities are "sectors"

# calculate the "A" partition size
# "A" should begin at 1 qty. sectors/track away from beginning
# The size should be 512MB  (B will be whatever is reamaining)

echo -n "A slice size offset in MB [${A_SLICE_MB_DEFAULT}]: "
read a_mb_tmp

if [ "x$a_mb_tmp" == "x" ]; then 
	A_SLICE_MB=${A_SLICE_MB_DEFAULT}
else
	A_SLICE_MB=$a_mb_tmp
fi

# Old Manual Adjustments
# A = 512mb
# 1k = 2 blocks
# 1024k = 1mb = 2048 blocks
# 512m * 1024 = 524288 bytes * 2 = 1048576 blocks
# 192m * 1024 = 196608 bytes * 2 = 393216 blocks
# Question: Do we need to stay on cylinder boundries?
#a_blocks=`expr 2048 \* $sectors_cylinder`
#a_blocks=1048576
#a_blocks=393216

# nasty assumption of 512b sector size
a_blocks=$((${A_SLICE_MB} * 2048)) 
a_bytes=`expr $a_blocks \* $bytes`

# start our minimal swap partition
b_offset=`expr $a_blocks + $sectors_cylinder`

b_blocks=`expr $total_blocks_usable \- $b_offset`
b_bytes=`expr $b_blocks \* $bytes`

cat << __EOF
----------

Here are the final settings for the image in terms of partition map
and filesystem settings.  Please review and press control-c to quit if
there are any problems.  If you don't understand any of this then just
press enter.

Partition Map:
      bytes per sector: $bytes
             cylinders: $cylinders
   tracks per cylinder: $tracks_cylinder
     sectors per track: $sectors_track
  sectors per cylinder: $sectors_cylinder
    total image blocks: $total_blocks
     total image bytes: $total_bytes
    total usable blocks: $total_blocks_usable
     total usable bytes: $total_bytes_usable

Disklabel:
  partition 'a' offset: 63
  partition 'a' blocks: $a_blocks
   partition 'a' bytes: $a_bytes
  partition 'b' offset: $b_offset
  partition 'b' blocks: $b_blocks
   partition 'b' bytes: $b_bytes
__EOF

case $PLATFORM in
	netbsd)
		cat << __EOF
  partition 'c' offset: $sectors_track
  partition 'c' blocks: $total_blocks_usable
   partition 'c' bytes: $total_bytes_usable
  partition 'd' offset: 0
  partition 'd' blocks: $total_blocks
   partition 'd' bytes: $total_bytes
__EOF
	;;
	openbsd)
		cat << __EOF
  partition 'c' offset: 0
  partition 'c' blocks: $total_blocks
   partition 'c' bytes: $total_bytes
__EOF
	;;
esac


echo -n "Press enter to continue or press control-c to quit and correct. "
read doit

#################################################

cat << __EOF
----------
Enter the vnode device to use.  If you do not know what this is then
just press enter to take the default of "$VNODE_DEV".

__EOF
echo -n "Vnode device [$VNODE_DEV]: "
read vnode_device
if [ "$vnode_device" = "" ]; then
    vnode_device=$VNODE_DEV
fi

#################################################

cat << __EOF
----------
Enter the directory path to the files that you want to load into the
CF image.  The default is the directory $DEFAULT_ROOT in the current directory.
It is assumed that this directory has the kernel files, boot
configuration files, and all other information necessary for the
system to work.  The directory should hold the following boot files in
these specific relevant places.  If you are using the root directory
then the following files should exist:

    # second-stage boot program to be installed in /
    $DEFAULT_ROOT/$SECOND_BOOT
    # first-stage boot program installed in the boot block
    $DEFAULT_ROOT/$FIRST_BOOT
    # alternate master-boot-record template file for fdisk
    $DEFAULT_ROOT/$MBR_TEMPLATE

__EOF

default_root=$CF_ROOT
if [ ! -d $default_root ]; then
    default_root=$CF_ROOT
fi

echo -n "Root filesystem directory [$default_root]: "
read root_dir

if [ "$root_dir" = "" ]; then
    root_dir=$default_root
fi

if [ ! -d $root_dir ]; then
    echo "I cannot see the directory $root_dir"
    exit 1
fi

############################################################################

# create the image file
echo "----------"
doit=yes
if [ -f $image_file ]; then
    echo -n "Image file $image_file exists.  Re-zero or re-create it? [yes] "
    read doit
    if [ "$doit" = "" ]; then
	doit=yes
    fi
fi

# Step X
if [ "$doit" = "yes" ]; then
    echo "Step ${_intStepCount}: Creating image file $image_file"
    rm -f $image_file
    dd if=/dev/zero of=$image_file bs=512 count=$total_blocks; good2go $?
fi

#################################################

# Now map it into the vnode device
# NetBSD requires the proper geomspec to get the geometry right
# a big thanks to Steven M. Bellovin <smb@cs.columbia.edu> for the tip
#

echo "Step ${_intStepCount}: Mapping $image_file to vnode device $vnode_device."
case $PLATFORM in
	netbsd)
		NETBSD_GEOMSPEC="512/$sectors_track/$tracks_cylinder/$cylinders"
		;;
esac

vnconfig $vnode_device $image_file $NETBSD_GEOMSPEC ; good2go $?

#################################################

# configure the partitions
echo "Step ${_intStepCount}: Updating the partition map for $vnode_device"

# It has become increasingly clear to me that the end
# draws near (and that this command does not work)

# We should come back and revisit this, since all I'm doing
# with the interactive __EOF shit below is precisely what
# I'm asking to be done with switches here.

#fdisk -b $cylinders/$tracks_cylinder/$sectors_track -v -f -u \
#	-s 169/$sectors_track/$total_blocks_usable -i -a -0 -c \
#	$root_dir/$MBR_TEMPLATE $vnode_device

echo "DEBUG platform variable: $PLATFORM"
echo
case $PLATFORM in
	netbsd)
		# Begin OpenBSD fdisk(8) technique
		echo "Step ${_intStepCount}:  Updating MBR partition map for vnode device $vnode_device"
		/sbin/fdisk -0ui $vnode_device <<  __EOF
n
169



y
y

__EOF
		echo "Step ${_intStepCount}:  Updating Active Partition Selection for $vnode_device failed."
		/sbin/fdisk -a0 $vnode_device << __EOF
y
0
y
y

__EOF
		;;
	openbsd)
		echo "Step ${_intStepCount}:  Updating MBR partition map and Active Partition for vnode device $vnode_device"
/sbin/fdisk -c $cylinders -h $tracks_cylinder -s $sectors_track -i -f $BOOTMBR $vnode_device << __EOF
y

__EOF
		good2go $?
		;;
esac

#################################################

# create the disk label
echo "Step ${_intStepCount}: Creating disk label for $vnode_device."

cat >> $DISKLABEL_TMP << __EOF
type: SCSI
disk: vnd device
label: fictitious
flags:
bytes/sector: 512
sectors/track: $sectors_track
tracks/cylinder: $tracks_cylinder
sectors/cylinder: $sectors_cylinder
cylinders: $cylinders
total sectors: $total_blocks
rpm: 3600
interleave: 1
trackskew: 0
cylinderskew: 0
headswitch: 0           # microseconds
track-to-track seek: 0  # microseconds
drivedata: 0 

16 partitions:
#        size        offset         fstype   [fsize bsize   cpg]
  a:   $a_blocks     $sectors_track 4.2BSD    0  0  
  b:   $b_blocks     $b_offset      4.2BSD    0  0  
__EOF

case $PLATFORM in
	netbsd)
cat >> $DISKLABEL_TMP << __EOF
  c:   $total_blocks_usable $sectors_track unused    0     0
  d:   $total_blocks 0              unused    0     0
__EOF
	;;
	openbsd)
cat >> $DISKLABEL_TMP << __EOF
  c:   $total_blocks_usable 0  unused    0     0
__EOF
	;;
esac

# DEBUG:if you want to display the label before writing, uncomment this
# echo "DEBUG: Disklabel cat
#cat $DISKLABEL_TMP

#################################################

# now write the disklabel
echo "Step ${_intStepCount}: Writing the disklabel to $vnode_device."
disklabel -R $vnode_device $DISKLABEL_TMP; good2go $?

#################################################

# adjust here for multiple slices
# Also wack all of the geometry-specific newfs(8) flags 
# since they're NBSD defaults in favor of specifying UFS1

for slice in a b; do 
	# creating new filesystem
	echo "----------"
	echo "Step ${_intStepCount}: Creating filesystem on /dev/r${vnode_device}${slice}"
	newfs /dev/r${vnode_device}${slice}; good2go $?
done

disklabel /dev/r${vnode_device}

#################################################

# making the new filesystem directory
for slice in a b; do
	echo "----------"
	echo "Step ${_intStepCount}: Making mount directory $VNODE_MOUNT${slice}."
	mkdir $VNODE_MOUNT${slice}; good2go $?
done;

#################################################

# mounting the new filesystem
for slice in a b; do 
	echo "----------"
	echo "Step ${_intStepCount}: Mounting vnode device /dev/r${vnode_device}${slice} on directory $VNODE_MOUNT."
	mount /dev/${vnode_device}${slice} $VNODE_MOUNT${slice}; good2go $?
done;

#################################################


# we need to copy the boot into place first probably so it can be
# contiguous and at a specific place on the disk early for the
# bootstrap code.

# This isn't nessecarily true on NetBSD.  OpenBSD requires installboot(8) to
# be aware of the block positions of the 2nd stage boot loader (/boot)
# when it writes the first stage bootloader (which, come to think of it
# is actually the 3rd stage boot loader, since mbr runs first, but anyway)
# Anyway, we're going with their technique because it's the new black(r).

echo "----------"
echo "Step ${_intStepCount}: Copying boot file from $BOOT_STAGE_2 into ${VNODE_MOUNT}a."
cp $BOOT_STAGE_2 $BOOTBLOCK ${VNODE_MOUNT}a; good2go $?

#################################################


# NetBSD specific:
# *) Use the raw device (learned in 2004 during the RAID1 tutorial)
# *) Chagne the installboot(8) syntax, specify a 1st boot (2nd argument) boot 
#    even though it is not nessecary

# install the boot blocks
echo "----------"
echo "Step ${_intStepCount}: Installing boot blocks on $vnode_device."
case $PLATFORM in
	netbsd)
		/usr/sbin/installboot -v -o timeout=1 /dev/r${vnode_device}a ${VNODE_MOUNT}a/$FIRST_BOOT ${VNODE_MOUNT}a/$SECOND_BOOT  ; good2go $?
	;;
	openbsd)
		/usr/mdec/installboot -v ${VNODE_MOUNT}a/$SECOND_BOOT ${VNODE_MOUNT}a/$FIRST_BOOT ${vnode_device} ; good2go $?
	;;
esac
		

#################################################
echo "----------"
echo "Step ${_intStepCount}: Copying the files from $root_dir into ${VNODE_MOUNT}a"
cd $root_dir
$PAX -rw -pe . ${HOME_DIR}/${VNODE_MOUNT}a; good2go $?
cd ${HOME_DIR}

echo "----------"
echo "Step ${_intStepCount}: Populating the shadow file system from ${HOME_DIR}/${SHADOW_PREFIX}"

if [ -d ${HOME_DIR}/${SHADOW_PREFIX} ]; then
	cd ${HOME_DIR}/${SHADOW_PREFIX}
	$PAX -rw -pe . ${HOME_DIR}/${VNODE_MOUNT}b ; good2go $?
	cd $HOME_DIR
else
	echo "Cannot find ${HOME_DIR}/${SHADOW_PREFIX}"
fi


###############################################################################

echo "Step ${_intStepCount}: Attempting to unmount vnd moutns"

for slice in a b; do
	
	# unmounting the image
	echo "Unmounting ${VNODE_MOUNT}${slice}."
	sync
	umount ${VNODE_MOUNT}${slice}; good2go $?

	echo "Removing ${VNODE_MOUNT}${slice} directory."
	rmdir ${VNODE_MOUNT}${slice}
	if [ $? -ne 0 ]; then
	    echo "Remolving directory ${VNODE_MOUNT}${slice} failed."
	    # continue
	fi
done
	
# removing the vnode
echo "Removing vnode device $vnode_device."
vnconfig -u $vnode_device; good2go $?

# sync to disk
sync
